package com.yupi.springbootinit.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import com.yupi.springbootinit.annotation.AuthCheck;
import com.yupi.springbootinit.bizmq.BiMessageProducer;
import com.yupi.springbootinit.common.*;
import com.yupi.springbootinit.constant.UserConstant;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.exception.ThrowUtils;
import com.yupi.springbootinit.manager.BigModelNew;
import com.yupi.springbootinit.manager.RedisLimiterManager;
import com.yupi.springbootinit.mapper.ChartMapper;
import com.yupi.springbootinit.mapper.DynamicChartMapper;
import com.yupi.springbootinit.model.dto.chart.*;
import com.yupi.springbootinit.model.entity.Chart;
import com.yupi.springbootinit.model.entity.User;
import com.yupi.springbootinit.model.vo.BiResponse;
import com.yupi.springbootinit.model.vo.ChartVO;
import com.yupi.springbootinit.service.ChartService;
import com.yupi.springbootinit.service.UserService;
import com.yupi.springbootinit.utils.ExcelUtils;
import com.yupi.springbootinit.utils.GetSql;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

import static com.yupi.springbootinit.constant.RedisConstants.CACHE_ALL_CHART;
import static com.yupi.springbootinit.constant.RedisConstants.CACHE_MY_CHART;
import static com.yupi.springbootinit.constant.UserConstant.USER_LOGIN_STATE;

/**
 * 帖子接口
 *
 *  
 */
@RestController
@RequestMapping("/chart")
@Slf4j
public class ChartController {

    @Resource
    private ChartService chartService;

    @Resource
    private UserService userService;

    @Resource
    private BigModelNew bigModelNew;

    @Resource
    private ChartMapper chartMapper;

    @Resource
    // 自动注入一个线程池的实例
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private RedisLimiterManager redisLimiterManager;

    @Resource
    private BiMessageProducer biMessageProducer;

    @Resource
    private DynamicChartMapper dynamicChartMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    private final static Gson GSON = new Gson();


    /**
     * 创建
     *
     * @param chartAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    public BaseResponse<Long> addChart(@RequestBody ChartAddRequest chartAddRequest, HttpServletRequest request) {
        if (chartAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Chart chart = new Chart();
        BeanUtils.copyProperties(chartAddRequest, chart);
        User loginUser = userService.getLoginUser(request);
        chart.setUserId(loginUser.getId());
        boolean result = chartService.save(chart);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        long newChartId = chart.getId();
        return ResultUtils.success(newChartId);
    }

    /**
     * AI生成接口（异步 ，线程池）
     *
     * @param multipartFile
     * @param request
     * @return
     */
    @PostMapping("/getChar/async")
    @Transactional
    public BaseResponse<BiResponse> getCharByAiAsync(@RequestPart("file") MultipartFile multipartFile,
                                            GetCharByAiRequest getCharByAiRequest, HttpServletRequest request) {
        String chartType = getCharByAiRequest.getChartType();
        String chartName = getCharByAiRequest.getChartName();
        String userGoal = getCharByAiRequest.getGoal();

        ThrowUtils.throwIf(StringUtils.isBlank(chartType), ErrorCode.PARAMS_ERROR,"类型为空");
        ThrowUtils.throwIf(StringUtils.isBlank(chartName), ErrorCode.PARAMS_ERROR,"目标名称为空");
        ThrowUtils.throwIf(StringUtils.isNotBlank(chartName) && chartName.length() > 100, ErrorCode.PARAMS_ERROR,"目标名称过长");
        ThrowUtils.throwIf(StringUtils.isBlank(userGoal), ErrorCode.PARAMS_ERROR,"用户目标为空");
        // 对文件校验，文件大小
        //todo 校验文件合法性 文件内容
        long size = multipartFile.getSize();
        final long fileSize = 1024 * 1024L;
        ThrowUtils.throwIf(size > fileSize, ErrorCode.PARAMS_ERROR,"文件超过1M");
        //校验文件类型
        String filename = multipartFile.getOriginalFilename();
        String suffix = FileUtil.getSuffix(filename);
        final List<String> validFilename = Arrays.asList("xls","xlsx");
        boolean contains = validFilename.contains(suffix);
        ThrowUtils.throwIf(!contains, ErrorCode.PARAMS_ERROR,"文件类型非法");
        // 通过response对象拿到用户id(必须登录才能使用)
        User loginUser = userService.getLoginUser(request);
        //文件的唯一性校验：当前用户+文件名+图表类型
        Long userId = loginUser.getId();
        LambdaQueryWrapper<Chart> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Chart::getUserId,userId);
        queryWrapper.eq(Chart::getFilename,filename);
        queryWrapper.eq(Chart::getChartType,chartType);
        Chart isChart = chartService.getOne(queryWrapper);
        ThrowUtils.throwIf(isChart != null, ErrorCode.PARAMS_ERROR,"该图表已生成，请查收");
        //接口限流
        redisLimiterManager.doRateLimit("getCharByAi_"+userId);

        //为ai设置题词预设
        /*
          用户的输入(参考)
          分析需求：
          分析网站用户的增长情况,请使用 ‘折线图’
          原始数据：
          日期,用户数
          1号,10
          2号,20
          3号,30
       */
        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        if(StrUtil.isNotBlank(chartType)){
            userGoal += "请使用" + chartType;
        }
        userInput.append(userGoal).append("\n");
        userInput.append("原始数据：").append("\n");
        //将excel文本处理为csv数据(压缩精简excel数据)，便于ai分析
        String csvData = ExcelUtils.ExcelToCsv(multipartFile);
        log.info("csv数据展示：{}",csvData);
        userInput.append(csvData).append("\n");

        //请求前，处理状态为等待，返回图表id到前端
        Chart preChart = new Chart();
        preChart.setChartName(chartName);
        preChart.setGoal(userGoal);
        preChart.setChartType(chartType);
        preChart.setUserId(loginUser.getId());
        preChart.setFilename(filename);
        preChart.setStatus(ChartStatus.WAIT.toString());
        boolean saveResult = chartService.save(preChart);
        if(!saveResult) {
            handleChartUpdateError(preChart.getId(),"图表等待状态更新失败");
        }
        //插入到具体图表表中，实现一个图表一个数据表
        Long chartId = preChart.getId();
        //生成创建表的sql 并执行
        String createSql = GetSql.createSql(chartId.toString(), csvData);
        chartMapper.createChart(createSql);
        //生成插入内容的sql 并执行
        List<String> insertSql = GetSql.insertSql(chartId.toString(), csvData);
        for(String sql:insertSql){
            chartMapper.insertChart(sql);
        }


        //ai处理由异步化执行
        CompletableFuture.runAsync(() -> {
            //请求时，处理状态为处理中
            Chart charting = new Chart();
            charting.setId(chartId);
            charting.setStatus(ChartStatus.RUNNING.toString());
            boolean saveing = chartService.updateById(charting);
            if(!saveing) {
                handleChartUpdateError(chartId,"图表处理中...状态更新失败");
            }

            //获取ai答复，并处理文本
            String result = bigModelNew.sendMessageToXingHuo(userInput.toString());
            String[] splits = result.split("'【'");
            if(splits.length < 2){
                throw new BusinessException(ErrorCode.SYSTEM_ERROR,"AI异常，请重试");
            }
            String genChart = splits[1].trim();
            String genResult = splits[2].trim();


            //请求后，处理状态为成功
            Chart charted = new Chart();
            charted.setId(chartId);
            charted.setGenChart(genChart);
            charted.setGenResult(genResult);
            charted.setStatus(ChartStatus.SUCCEED.toString());
            boolean saved = chartService.updateById(charted);
            if(!saved) {
                handleChartUpdateError(chartId,"图表成功状态更新失败");
            }
        },threadPoolExecutor);
            BiResponse biResponse = new BiResponse();
            biResponse.setChartId(preChart.getId());
            return ResultUtils.success(biResponse);
    }



    /**
     * AI生成接口（同步 ）
     *
     * @param multipartFile
     * @param request
     * @return
     */
    @PostMapping("/getChar")
    @Transactional
    public BaseResponse<BiResponse> getCharByAi(@RequestPart("file") MultipartFile multipartFile,
                                                GetCharByAiRequest getCharByAiRequest, HttpServletRequest request) {
        String chartType = getCharByAiRequest.getChartType();
        String chartName = getCharByAiRequest.getChartName();
        String userGoal = getCharByAiRequest.getGoal();

        ThrowUtils.throwIf(StringUtils.isBlank(chartType), ErrorCode.PARAMS_ERROR,"类型为空");
        ThrowUtils.throwIf(StringUtils.isBlank(chartName), ErrorCode.PARAMS_ERROR,"目标名称为空");
        ThrowUtils.throwIf(StringUtils.isNotBlank(chartName) && chartName.length() > 100, ErrorCode.PARAMS_ERROR,"目标名称过长");
        ThrowUtils.throwIf(StringUtils.isBlank(userGoal), ErrorCode.PARAMS_ERROR,"用户目标为空");
        // 对文件校验，文件大小
        long size = multipartFile.getSize();
        final long fileSize = 1024 * 1024L;
        ThrowUtils.throwIf(size > fileSize, ErrorCode.PARAMS_ERROR,"文件超过1M");
        //校验文件类型
        String filename = multipartFile.getOriginalFilename();
        String suffix = FileUtil.getSuffix(filename);
        final List<String> validFilename = Arrays.asList("png","xlsx");
        boolean contains = validFilename.contains(suffix);
        ThrowUtils.throwIf(!contains, ErrorCode.PARAMS_ERROR,"文件类型非法");
        // 通过response对象拿到用户id(必须登录才能使用)
        User loginUser = userService.getLoginUser(request);
        //文件的唯一性校验：当前用户+文件名+图表类型
        Long userId = loginUser.getId();
        LambdaQueryWrapper<Chart> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Chart::getUserId,userId);
        queryWrapper.eq(Chart::getFilename,filename);
        queryWrapper.eq(Chart::getChartType,chartType);
        Chart isChart = chartService.getOne(queryWrapper);
        ThrowUtils.throwIf(isChart != null, ErrorCode.PARAMS_ERROR,"该图表已生成，请查收");
        //接口限流
        redisLimiterManager.doRateLimit("getCharByAi_"+userId);

        //为ai设置题词预设
        /*
          用户的输入(参考)
          分析需求：
          分析网站用户的增长情况,请使用 ‘折线图’
          原始数据：
          日期,用户数
          1号,10
          2号,20
          3号,30
       */
        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        if(StrUtil.isNotBlank(chartType)){
            userGoal += "请使用" + chartType;
        }
        userInput.append(userGoal).append("\n");
        userInput.append("原始数据：").append("\n");
        //将excel文本处理为csv数据(压缩精简excel数据)，便于ai分析
        String csvData = ExcelUtils.ExcelToCsv(multipartFile);
        log.info("csv数据展示：\n {}",csvData);
        userInput.append(csvData).append("\n");
        //向ai发送请求
            String result = bigModelNew.sendMessageToXingHuo(userInput.toString());
            String[] splits = result.split("'【'");
            if(splits.length < 2){
                throw new BusinessException(ErrorCode.SYSTEM_ERROR,"AI异常，请重试");
            }

            String genChart = splits[1].trim();
            String genResult = splits[2].trim();

            //格式化json字符串，保证页面正确显示
            Gson gson = new GsonBuilder().setPrettyPrinting().create();
            String jsonGenChart = gson.toJson(JsonParser.parseString(genChart));

            // 插入到数据库
            Chart chart = new Chart();
            chart.setChartName(chartName);
            chart.setGoal(userGoal);
            chart.setChartType(chartType);
            chart.setGenChart(jsonGenChart);
            chart.setGenResult(genResult);
            chart.setUserId(loginUser.getId());
            chart.setFilename(filename);
            chart.setStatus(ChartStatus.SUCCEED.toString());
            boolean saveResult = chartService.save(chart);
            //插入到具体图表表中，实现一个图表一个数据表
            Long chartId = chart.getId();
            //生成创建表的sql 并执行
            String createSql = GetSql.createSql(chartId.toString(), csvData);
            chartMapper.createChart(createSql);
            //生成插入内容的sql 并执行
            List<String> insertSql = GetSql.insertSql(chartId.toString(), csvData);
            for(String sql:insertSql){
                chartMapper.insertChart(sql);
            }
            ThrowUtils.throwIf(!saveResult, ErrorCode.SYSTEM_ERROR, "图表保存失败");

            //添加成功，删除页缓存
            //判断当前用户角色，普通用户添加图表，则删除当前用户和 管理员分页键，管理员添加图表，仅删除管理员的键
            User user = (User)request.getSession().getAttribute(USER_LOGIN_STATE);
            Set<String> allKeys = new HashSet<>();
            if("user".equals(user.getUserRole())) {
                String key1 = CACHE_MY_CHART+user.getId()+"_*";
                String key2 = CACHE_ALL_CHART +"*";
                Set<String>  keys1 = stringRedisTemplate.keys(key1);
                Set<String>  keys2 = stringRedisTemplate.keys(key2);
                allKeys.addAll(keys2);
                allKeys.addAll(keys1);
            }
            if("admin".equals(user.getUserRole())) {
                String key = CACHE_ALL_CHART+"*";
                allKeys = stringRedisTemplate.keys(key);
            }

            if(allKeys != null && !allKeys.isEmpty()){
                stringRedisTemplate.delete(allKeys);
            }

            BiResponse biResponse = new BiResponse();
            biResponse.setGenChart(jsonGenChart);
            biResponse.setGenResult(genResult);
            biResponse.setChartId(chart.getId());
            return ResultUtils.success(biResponse);

    }


    /**
     * AI生成接口（异步 ，rabbit）
     *
     * @param multipartFile
     * @param request
     * @return
     */
    @PostMapping("/getChar/asyncRabbit")
    @Transactional
    public BaseResponse<BiResponse> getCharByAiAsyncRabbit(@RequestPart("file") MultipartFile multipartFile,
                                                     GetCharByAiRequest getCharByAiRequest, HttpServletRequest request) {
        String chartType = getCharByAiRequest.getChartType();
        String chartName = getCharByAiRequest.getChartName();
        String userGoal = getCharByAiRequest.getGoal();

        ThrowUtils.throwIf(StringUtils.isBlank(chartType), ErrorCode.PARAMS_ERROR,"类型为空");
        ThrowUtils.throwIf(StringUtils.isBlank(chartName), ErrorCode.PARAMS_ERROR,"目标名称为空");
        ThrowUtils.throwIf(StringUtils.isNotBlank(chartName) && chartName.length() > 100, ErrorCode.PARAMS_ERROR,"目标名称过长");
        ThrowUtils.throwIf(StringUtils.isBlank(userGoal), ErrorCode.PARAMS_ERROR,"用户目标为空");
        // 对文件校验，文件大小
        long size = multipartFile.getSize();
        final long fileSize = 1024 * 1024L;
        ThrowUtils.throwIf(size > fileSize, ErrorCode.PARAMS_ERROR,"文件超过1M");
        //校验文件类型
        String filename = multipartFile.getOriginalFilename();
        String suffix = FileUtil.getSuffix(filename);
        final List<String> validFilename = Arrays.asList("xls","xlsx");
        boolean contains = validFilename.contains(suffix);
        ThrowUtils.throwIf(!contains, ErrorCode.PARAMS_ERROR,"文件类型非法");
        // 通过response对象拿到用户id(必须登录才能使用)
        User loginUser = userService.getLoginUser(request);
        //文件的唯一性校验：当前用户+文件名+图表类型
        Long userId = loginUser.getId();
        LambdaQueryWrapper<Chart> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Chart::getUserId,userId);
        queryWrapper.eq(Chart::getFilename,filename);
        queryWrapper.eq(Chart::getChartType,chartType);
        Chart isChart = chartService.getOne(queryWrapper);
        ThrowUtils.throwIf(isChart != null, ErrorCode.PARAMS_ERROR,"该图表已生成，请查收");
        //接口限流
        redisLimiterManager.doRateLimit("getCharByAi_"+userId);

        //为ai设置题词预设
        /*
          用户的输入(参考)
          分析需求：
          分析网站用户的增长情况,请使用 ‘折线图’
          原始数据：
          日期,用户数
          1号,10
          2号,20
          3号,30
       */
        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        if(StrUtil.isNotBlank(chartType)){
            userGoal += "请使用" + chartType;
        }
        userInput.append(userGoal).append("\n");
        userInput.append("原始数据：").append("\n");
        //将excel文本处理为csv数据(压缩精简excel数据)，便于ai分析
        String csvData = ExcelUtils.ExcelToCsv(multipartFile);
        log.info("csv数据展示：{}",csvData);
        userInput.append(csvData).append("\n");

        //请求前，处理状态为等待，返回图表id到前端
        Chart preChart = new Chart();
        preChart.setChartName(chartName);
        preChart.setGoal(userGoal);
        preChart.setChartType(chartType);
        preChart.setUserId(loginUser.getId());
        preChart.setFilename(filename);
        preChart.setStatus(ChartStatus.WAIT.toString());
        boolean saveResult = chartService.save(preChart);
        if(!saveResult) {
            handleChartUpdateError(preChart.getId(),"图表等待状态更新失败");
        }
        //插入到具体图表表中，实现一个图表一个数据表
        Long chartId = preChart.getId();
        //生成创建表的sql 并执行
        String createSql = GetSql.createSql(chartId.toString(), csvData);
        chartMapper.createChart(createSql);
        //生成插入内容的sql 并执行
        List<String> insertSql = GetSql.insertSql(chartId.toString(), csvData);
        for(String sql:insertSql){
            chartMapper.insertChart(sql);
        }
        //更新redis缓存
        //添加成功，删除页缓存
        //判断当前用户角色，普通用户添加图表，则删除当前用户和 管理员分页键，管理员添加图表，仅删除管理员的键
        Set<String> allKeys = new HashSet<>();
        if("user".equals(loginUser.getUserRole())) {
            String key1 = CACHE_MY_CHART+loginUser.getId()+"_*";
            String key2 = CACHE_ALL_CHART +"*";
            Set<String>  keys1 = stringRedisTemplate.keys(key1);
            Set<String>  keys2 = stringRedisTemplate.keys(key2);
            allKeys.addAll(keys2);
            allKeys.addAll(keys1);
        }
        if("admin".equals(loginUser.getUserRole())) {
            String key = CACHE_ALL_CHART+"*";
            allKeys = stringRedisTemplate.keys(key);
        }

        if(allKeys != null && !allKeys.isEmpty()){
            stringRedisTemplate.delete(allKeys);
        }


        //发送 具体某个图表id,csvData给队列消费，队列根据id休闲时生成ai文本
        //发送 当前用户id，用于判断是否删除缓存
        biMessageProducer.sendMessage(csvData,chartId.toString(),loginUser.getId().toString());

        BiResponse biResponse = new BiResponse();
        biResponse.setChartId(preChart.getId());
        return ResultUtils.success(biResponse);
    }


    public void handleChartUpdateError(long charId,String execMessage) {
        Chart chartError= new Chart();
        chartError.setId(charId);
        chartError.setExecMessage(execMessage);
        chartError.setStatus(ChartStatus.FAILED.toString());
        boolean saved = chartService.updateById(chartError);
        if(!saved){
            log.info("图表失败状态更新失败。id: "+charId+execMessage);
        }
    }

    /**
     * 删除
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteChart(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User user = userService.getLoginUser(request);
        long id = deleteRequest.getId();
        // 判断是否存在
        Chart oldChart = chartService.getById(id);
        ThrowUtils.throwIf(oldChart == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可删除
        if (!oldChart.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean b = chartService.removeById(id);
        if(!b){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }

        //删除操作-删除当前用户，管理员分页的key
        String key1 = CACHE_MY_CHART+user.getId()+"_*";
        String key2 = CACHE_ALL_CHART +"*";
        Set<String> allKeys = new HashSet<>();
        Set<String>  keys1 = stringRedisTemplate.keys(key1);
        Set<String>  keys2 = stringRedisTemplate.keys(key2);
        allKeys.addAll(keys2);
        allKeys.addAll(keys1);
        if(allKeys != null && !allKeys.isEmpty()){
            stringRedisTemplate.delete(allKeys);
        }

        return ResultUtils.success(b);
    }

    /**
     * 更新（仅管理员）
     *
     * @param chartUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateChart(@RequestBody ChartUpdateRequest chartUpdateRequest,HttpServletRequest request){
        if (chartUpdateRequest == null || chartUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Chart chart = new Chart();
        BeanUtils.copyProperties(chartUpdateRequest, chart);
        long id = chartUpdateRequest.getId();
        // 判断是否存在
        Chart oldChart = chartService.getById(id);
        ThrowUtils.throwIf(oldChart == null, ErrorCode.NOT_FOUND_ERROR);
        redisLimiterManager.doRateLimit("getCharByAi_"+chart.getId());

        boolean result = false;
        try {
            result = chartService.updateChartById(chart,request);
            if(!result){
                throw new BusinessException(ErrorCode.TOO_MANY_REQUEST);
            }
        } catch (Exception e) {
            log.info("捕获异常：{}",e.getMessage());
            throw new RuntimeException(e);
        }
        return ResultUtils.success(result);
    }

    /**
     * 根据 id 获取
     *
     * @param id
     * @return
     */
    @GetMapping("/get")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<ChartVO> getChartById(long id, HttpServletRequest request) {
        ChartVO chartVO = chartService.getChartById(id);
        return ResultUtils.success(chartVO);
    }

    /**
     * 分页获取列表（封装类）
     *
     * @param chartQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page")
    public BaseResponse<Page<ChartDto>> listChartByPage(@RequestBody ChartQueryRequest chartQueryRequest,
            HttpServletRequest request) {
        Page<ChartDto> chartDtoPage = chartService.dtoPage(chartQueryRequest);
        return ResultUtils.success(chartDtoPage);
    }

    /**
     * 分页获取当前用户创建的资源列表
     *
     * @param chartQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/my/list/page")
    public BaseResponse<Page<Chart>> listMyChartByPage(@RequestBody ChartQueryRequest chartQueryRequest,
            HttpServletRequest request) {
        Page<Chart> chartPage = chartService.page(chartQueryRequest,request);
        return ResultUtils.success(chartPage);
    }



    /**
     * 编辑（用户）
     *
     * @param chartEditRequest
     * @param request
     * @return
     */
    @PostMapping("/edit")
    public BaseResponse<Boolean> editChart(@RequestBody ChartEditRequest chartEditRequest, HttpServletRequest request) {
        if (chartEditRequest == null || chartEditRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Chart chart = new Chart();
        BeanUtils.copyProperties(chartEditRequest, chart);
        User loginUser = userService.getLoginUser(request);
        long id = chartEditRequest.getId();
        // 判断是否存在
        Chart oldChart = chartService.getById(id);
        ThrowUtils.throwIf(oldChart == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可编辑
        if (!oldChart.getUserId().equals(loginUser.getId()) && !userService.isAdmin(loginUser)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean result = chartService.updateById(chart);
        return ResultUtils.success(result);
    }
    //todo 添加缓存 缓存已经生成的图表
    //todo 定时任务 定期处理失败的图表
    // todo 微服务拆分，多个消费者，多台服务器消费
    //todo 对单用户生成的图表数量做限制

}
